<?php

namespace app\services;

use app\payment\PayFactory;
use plugin\admin\app\model\FreezeIntegralReleaseLog;
use plugin\admin\app\model\ShareSpeedUpRate;
use plugin\admin\app\model\TeamSpeedUpConfig;
use plugin\admin\app\model\TeamSpeedUpLog;
use plugin\admin\app\model\User;
use plugin\admin\app\model\UserProfile;
use plugin\admin\app\model\UserProperty;
use plugin\admin\app\model\UserPropertyLog;
use plugin\admin\app\model\UserTeam;

class PropertyService
{

    public static function reduce($userId, $propertyType, $amount, $source, $remark = '', $orderNo = '')
    {
        $user = UserProperty::where('user_id', $userId)->first();

        if (! $user) {
            throw new \Exception('不存在的用户');
        }

        if (bcsub($user[$propertyType], $amount, 2) < 0) {
            throw new \Exception('资产不足');
        }

        UserProperty::where('user_id', $userId)->decrement($propertyType, $amount);

        UserPropertyLog::insert([
            'user_id' => $userId,
            'source' => $source,
            'type' => $propertyType,
            'before' => $user[$propertyType],
            'amount' => -$amount,
            'remark' => $remark,
            'order_no' => $orderNo,
            'created_time' => date('Y-m-d H:i:s')
        ]);
    }

    public static function add($userId, $propertyType, $amount, $source, $remark = '', $orderNo = '', $rewardType = 0, $fromUserId = 0)
    {
        $user = UserProperty::where('user_id', $userId)->first();

        if (! $user) {
            UserProperty::insert(['user_id' => $userId]);
        }

        UserProperty::where('user_id', $userId)->increment($propertyType, $amount);

        $data = [
            'user_id' => $userId,
            'source' => $source,
            'type' => $propertyType,
            'before' => $user[$propertyType],
            'amount' => $amount,
            'remark' => $remark,
            'order_no' => $orderNo,
            'created_time' => date('Y-m-d H:i:s'),
            'from_user_id' => $fromUserId
        ];

        if ($rewardType) {
            $data['reward_type'] = $rewardType;
        }

        UserPropertyLog::insert($data);
    }

    public static function transfer($from, $to, $propertyType, $amount, $remark = '', $orderNo = '')
    {
        switch ($propertyType) {
            case PayFactory::RECHARGE_INTEGRAL:
                $reduceSource = UserPropertyLog::RECHARGE_INTEGRAL_GIVE;
                $addSource = UserPropertyLog::RECHARGE_INTEGRAL_RECEIVE;
                break;
            case PayFactory::REGISTER_INTEGRAL:
                $reduceSource = UserPropertyLog::REGISTER_INTEGRAL_GIVE;
                $addSource = UserPropertyLog::REGISTER_INTEGRAL_RECEIVE;
                break;
            default:
                throw new \Exception('不支持转赠的资产类型');
        }

        self::reduce($from, $propertyType, $amount, $reduceSource, $remark, $orderNo);
        self::add($to, $propertyType, $amount, $addSource, $remark, $orderNo);
    }

    public static function integralToRegisterIntegral($amount)
    {
        self::reduce(get_user_id(), PayFactory::INTEGRAL, $amount, UserPropertyLog::INTEGRAL_TO_REGISTER_INTEGRAL);
        self::add(get_user_id(), PayFactory::REGISTER_INTEGRAL, $amount, UserPropertyLog::REGISTER_INTEGRAL_FROM_INTEGRAL);
    }

    public static function teamReleaseFreezeIntegral($userId)
    {
        $propertyInfo = UserProperty::where('user_id', $userId)->first();

        //剩余释放
        $restIntegral = bcsub($propertyInfo['freeze_integral'], $propertyInfo['unfreeze_integral'], 2);

        $list = TeamReleaseLogService::list($userId);

        foreach ($list as $item) {
            $config = json_decode($item['config'], true);

            $releaseAmount = bcmul($config['integral'], $item['recommend_count'], 2);

            $actualReleaseAmount = $shouldReleaseAmount = $releaseAmount;

            //如果剩余额度不够释放，累计欠的额度，下次购买礼包后立即释放
            $borrowAmount = bcsub($releaseAmount, $restIntegral, 2);

            if ($borrowAmount > 0) {    //如果欠额度
                PropertyService::add($userId, PayFactory::BORROW_INTEGRAL, $borrowAmount, UserPropertyLog::BORROW_INTEGRAL_ADD_TEAM, '');

                if ($borrowAmount == $shouldReleaseAmount) {  //如果欠的额度完全等于释放额度，则无可释放额度
                    $actualReleaseAmount = 0;
                } else {    //如果欠的额度小于释放额度，则剩余额度继续释放
                    $actualReleaseAmount = $restIntegral;
                }
            }

            TeamReleaseLogService::incrementDays($item['id']);

            if ($actualReleaseAmount <= 0) {
                continue;
            }

            $inviteUserIds = array_filter(explode(',', $item['invite_user_ids']));

            $actualAmount = $actualReleaseAmount;

            foreach ($inviteUserIds as $inviteUserId) {
                if ($actualReleaseAmount <= 0) {
                    break;
                }

                if ($actualReleaseAmount >= $config['integral']) {
                    $amount = $config['integral'];
                    $actualReleaseAmount = bcsub($actualReleaseAmount, $config['integral'], 2);
                } else {
                    $amount = $actualReleaseAmount;
                    $actualReleaseAmount = 0;
                }

                PropertyService::add($userId, PayFactory::INTEGRAL, $amount, UserPropertyLog::INTEGRAL_FROM_FREEZE_INTEGRAL_RELEASE_TEAM, '', '', 0, $inviteUserId);
                PropertyService::add($userId, PayFactory::UNFREEZE_INTEGRAL, $amount, UserPropertyLog::UNFREEZE_INTEGRAL_RELEASE_TEAM, '', '', 0, $inviteUserId);

            }

            FreezeIntegralReleaseLog::insert([
                'user_id' => $userId,
                'total_amount_rate' => 0,
                'type' => FreezeIntegralReleaseLog::TEAM,
                'rates' => '',
                'actual_amount' => $actualAmount,
                'should_amount' => $shouldReleaseAmount,
                'before_amount' => $restIntegral,
                'rest_amount' => bcsub($restIntegral, $actualAmount, 2),
                'remark' => sprintf("%dx%d", $config['integral'], $item['recommend_count']),
                'created_time' => date('Y-m-d H:i:s')
            ]);

            TeamReleaseLogService::incrementReleaseAmount($item['id'], $actualAmount);
        }
    }

    public static function borrowReleaseFreezeIntegral($userId)
    {
        $propertyInfo = UserProperty::where('user_id', $userId)->first();

        if ($propertyInfo['borrow_integral'] > 0) {
            $restIntegral = $propertyInfo['freeze_integral'] - $propertyInfo['unfreeze_integral'];

            $releaseAmount = min($propertyInfo['borrow_integral'], $restIntegral);

            PropertyService::add($userId, PayFactory::INTEGRAL, $releaseAmount, UserPropertyLog::INTEGRAL_FROM_FREEZE_INTEGRAL_RELEASE_BORROW, '');
            PropertyService::add($userId, PayFactory::UNFREEZE_INTEGRAL, $releaseAmount, UserPropertyLog::UNFREEZE_INTEGRAL_RELEASE_BORROW, '');
            PropertyService::reduce($userId, PayFactory::BORROW_INTEGRAL, $releaseAmount, UserPropertyLog::BORROW_INTEGRAL_REDUCE, '');

            FreezeIntegralReleaseLog::insert([
                'user_id' => $userId,
                'total_amount_rate' => 0,
                'type' => FreezeIntegralReleaseLog::BORROW,
                'rates' => '',
                'actual_amount' => $releaseAmount,
                'should_amount' => $releaseAmount,
                'before_amount' => $restIntegral,
                'rest_amount' => bcsub($restIntegral, $releaseAmount, 2),
                'remark' => '',
                'created_time' => date('Y-m-d H:i:s')
            ]);
        }
    }

    public static function releaseUserFreezeIntegral($type = 'share', $checkReleased = true)
    {
        if ($type == 'share') {
            $userPropertyList = UserProperty::whereRaw('freeze_integral > 0')->get()->toArray();

            foreach ($userPropertyList as $userProperty) {
                if ($checkReleased && self::isReleased(FreezeIntegralReleaseLog::SHARE, $userProperty['user_id'])) {
                    continue;
                }
                self::shareReleaseFreezeIntegral($userProperty['user_id']);
            }
        } elseif ($type == 'team') {
            $logs = TeamSpeedUpLog::select(['user_id'])->where('recommend_count', '>', 0)->where('status', 0)->get()->toArray();

            $userIds = array_column($logs, 'user_id');

            foreach ($userIds as $userId) {
                if ($checkReleased && self::isReleased(FreezeIntegralReleaseLog::TEAM, $userId)) {
                    continue;
                }
                self::teamReleaseFreezeIntegral($userId);
            }
        }
    }

    public static function isReleased($type, $userId, $date = null)
    {
        if (is_null($date)) {
            $date = date('Y-m-d');
        }

        $startTime = date('Y-m-d 00:00:00', strtotime($date));
        $endTime = date('Y-m-d 23:59:59', strtotime($date));
        if (FreezeIntegralReleaseLog::where('user_id', $userId)->where('type', $type)->whereBetween('created_time', [$startTime, $endTime])->count() > 0) {
            return true;
        }

        return false;
    }

    public static function shareReleaseFreezeIntegral($userId)
    {

        $propertyInfo = UserProperty::where('user_id', $userId)->first();

        //剩余释放额度
        $restIntegral = bcsub($propertyInfo['freeze_integral'], $propertyInfo['unfreeze_integral'], 2);

        $teamInfo = UserTeam::where('user_id', $userId)->first();

        //首充金额比例
        $amountRate = ConfigService::get('share_speed_up_rate');

        //基数
        $profile = UserProfile::where('user_id', $userId)->first();
        $baseAmount = bcmul($profile['first_time_recharge_integral'], $amountRate / 100, 2);

        //获取加速额度
        [$releaseAmount, $remark, $rates] = self::getReleaseAmount($userId, $teamInfo['recommend_vip_count'], $baseAmount);

        $actualReleaseAmount = $shouldReleaseAmount = $releaseAmount;

        //如果剩余额度不够释放，累计欠的额度，下次购买礼包后立即释放
        $borrowAmount = bcsub($releaseAmount, $restIntegral, 2);

        if ($borrowAmount > 0) {    //如果欠额度
            PropertyService::add($userId, PayFactory::BORROW_INTEGRAL, $borrowAmount, UserPropertyLog::BORROW_INTEGRAL_ADD, '');

            if ($borrowAmount == $shouldReleaseAmount) {  //如果欠的额度完全等于释放额度，则无可释放额度
                $actualReleaseAmount = 0;
            } else {    //如果欠的额度小于释放额度，则剩余额度继续释放
                $actualReleaseAmount = $restIntegral;
            }
        }

        if ($actualReleaseAmount <= 0) {
            return;
        }

        PropertyService::add($userId, PayFactory::INTEGRAL, $actualReleaseAmount, UserPropertyLog::INTEGRAL_FROM_FREEZE_INTEGRAL_RELEASE, '');
        PropertyService::add($userId, PayFactory::UNFREEZE_INTEGRAL, $actualReleaseAmount, UserPropertyLog::UNFREEZE_INTEGRAL_RELEASE, '');

        FreezeIntegralReleaseLog::insert([
            'user_id' => $userId,
            'total_amount_rate' => $amountRate,
            'type' => FreezeIntegralReleaseLog::SHARE,
            'rates' => $rates,
            'actual_amount' => $actualReleaseAmount,
            'should_amount' => $shouldReleaseAmount,
            'before_amount' => $restIntegral,
            'rest_amount' => bcsub($restIntegral, $actualReleaseAmount, 2),
            'remark' => $remark,
            'created_time' => date('Y-m-d H:i:s')
        ]);
    }

    public static function getReleaseAmount($userId, $count, $base)
    {
        $res = ShareSpeedUpRate::where('count', '<=', $count)->orderByDesc('count')->offset(0)->limit(1)->first();

        $rate = $res['rate'] ?? 0;

        $recommendUserIds = UserService::getRecommendUserIds($userId);
        $recommendUserPropertyList = UserProperty::whereIn('user_id', $recommendUserIds)->get()->toArray();

        $totalAmount = $base;
        $formula = [$base];
        $rates = [];
        $limitAmount = ConfigService::get('unfreeze_integral_limit_amount');

        foreach ($recommendUserPropertyList as $recommendUserProperty) {
            $currentRate = $rate;
            //已释放的积分大于某个值，降速
            if ($recommendUserProperty['unfreeze_integral'] >= $limitAmount) {
                $currentRate = ConfigService::get('after_speed_up_rate');
            }

            $amount = bcmul($base, $currentRate / 100, 2);
            $totalAmount = bcadd($totalAmount, $amount, 2);
            $formula[] = sprintf("%dx%d%%", $base, $currentRate);

            $rates[] = [
                'user_id' => $recommendUserProperty['user_id'],
                'rate' => $currentRate,
                'unfreeze_integral' => $recommendUserProperty['unfreeze_integral'],
            ];
        }

        return [$totalAmount, join('+', $formula), json_encode($rates, JSON_UNESCAPED_UNICODE)];
    }

    public static function getTeamReleaseRate($amount)
    {
        $res = TeamSpeedUpConfig::where('sale_amount', '<=', $amount)->orderByDesc('sale_amount')->offset(0)->limit(1)->first();

        return $res['integral'] ?? 0;
    }
}